package com.ibm.util;

import java.util.HashMap;

import scala.Char;

/**
 * @author Yaoliang Chen
 * @version May 15, 2014 Description
 */

public final class DataTypes {
	private static final int DT_UPPER = 64;

	private static final String DT_NAME_FLOAT = "float";
	private static final String DT_NAME_DOUBLE = "double";
	private static final String DT_NAME_INT = "int";
	private static final String DT_NAME_INT2 = "integer";
	private static final String DT_NAME_INT3 = "long";
	private static final String DT_NAME_STRING = "string";
	private static final String DT_NAME_STRING2 = "str";
	private static final String DT_NAME_BOOLEAN = "boolean";
	private static final String DT_NAME_BOOLEAN2 = "bool";
	
	// add and change the datamessage's type from comparable to object.
	private static final String DT_NAME_DOUBLE_ARRAY = "double[]";
	private static final String DT_NAME_INT_ARRAY = "int[]";
	private static final String DT_NAME_String_ARRAY = "string[]";
	
	private static final String DT_NAME_WILDCARD = "wildcard";

	public static final byte DT_DOUBLE = 1;
	/*
	 * public static final byte DT_FLOAT = 2; public static final byte DT_INT =
	 * 3;
	 * 
	 * public static final byte DT_SHORT = 4;
	 */
	public static final byte DT_LONG = 5;
	public static final byte DT_STRING = 6;
	public static final byte DT_BOOLEAN = 7;

	public static final byte DT_DOUBLE_LEN = 8;
	// public static final byte DT_FLOAT_LEN = 4;
	// public static final byte DT_INT_LEN = 4;

	// public static final byte DT_SHORT_LEN = 2;
	public static final byte DT_LONG_LEN = 8;
	// public static final byte DT_BYTE_LEN = 1;
	
	public static final byte DT_DOUBLE_ARRAY = 10;
	public static final byte DT_INT_ARRAY = 11;
	public static final byte DT_STRING_ARRAY = 12;
	
	public static final byte DT_WILDCARD = 13;
	

	public static final byte DT_DEFAULT = DT_DOUBLE;
	public static final String DT_NAME_DEFAULT = DT_NAME_DOUBLE;

	public static final byte[] sizeMap = new byte[DT_UPPER];
	public static final byte[][] nullMap = new byte[DT_UPPER][];

	public static final int FLOAT_NULL = 1;
	public static final long DOUBLE_NULL = 1;
	public static final long LONG_NULL = Long.MIN_VALUE;
	public static final int INT_NULL = Integer.MIN_VALUE;
	public static final short SHORT_NULL = Short.MIN_VALUE;
	public static final byte BYTE_NULL = Byte.MIN_VALUE;

	public static final byte[] FLOAT_NULL_BYTES = new byte[] { 0, 0, 0, 1 };
	public static final byte[] DOUBLE_NULL_BYTES = new byte[] { 0, 0, 0, 0, 0,
			0, 0, 1 };
	public static final byte[] LONG_NULL_BYTES = new byte[] { (byte) 0x80, 0,
			0, 0, 0, 0, 0, 0 };
	public static final byte[] INT_NULL_BYTES = new byte[] { (byte) 0x80, 0, 0,
			0 };
	public static final byte[] SHORT_NULL_BYTES = new byte[] { (byte) 0x80, 0 };
	public static final byte[] BYTE_NULL_BYTES = new byte[] { (byte) 0x80 };

	private static HashMap<String, Byte> dtMap = new HashMap<String, Byte>();
	private static HashMap<Byte, String> revertDTMap = new HashMap<Byte, String>();

	private static final String MAX_STRING = new String(
			new char[] { Char.MaxValue(), Char.MaxValue(), Char.MaxValue(),
					Char.MaxValue(), Char.MaxValue(), Char.MaxValue(),
					Char.MaxValue(), Char.MaxValue(), });

	private static final String MIN_STRING = new String(
			new char[] { Char.MinValue(), Char.MinValue(), Char.MinValue(),
					Char.MinValue(), Char.MinValue(), Char.MinValue(),
					Char.MinValue(), Char.MinValue(), });

	static {
		dtMap.put(DT_NAME_INT, DT_LONG);
		dtMap.put(DT_NAME_INT2, DT_LONG);
		dtMap.put(DT_NAME_INT3, DT_LONG);
		dtMap.put(DT_NAME_FLOAT, DT_DOUBLE);
		dtMap.put(DT_NAME_DOUBLE, DT_DOUBLE);
		dtMap.put(DT_NAME_STRING, DT_STRING);
		dtMap.put(DT_NAME_STRING2, DT_STRING);
		dtMap.put(DT_NAME_BOOLEAN, DT_BOOLEAN);
		dtMap.put(DT_NAME_BOOLEAN2, DT_BOOLEAN);

		dtMap.put(DT_NAME_DOUBLE_ARRAY,DT_DOUBLE_ARRAY);
		dtMap.put(DT_NAME_INT_ARRAY,DT_INT_ARRAY);
		dtMap.put(DT_NAME_String_ARRAY,DT_STRING_ARRAY);
		
		dtMap.put(DT_NAME_WILDCARD, DT_WILDCARD);
		
		revertDTMap.put(DT_LONG, DT_NAME_INT);
		revertDTMap.put(DT_DOUBLE, DT_NAME_DOUBLE);
		revertDTMap.put(DT_STRING, DT_NAME_STRING);
		revertDTMap.put(DT_BOOLEAN, DT_NAME_BOOLEAN);

		revertDTMap.put(DT_INT_ARRAY, DT_NAME_INT_ARRAY);
		revertDTMap.put(DT_DOUBLE_ARRAY, DT_NAME_DOUBLE_ARRAY);
		revertDTMap.put(DT_STRING_ARRAY, DT_NAME_String_ARRAY);
		
		revertDTMap.put(DT_WILDCARD, DT_NAME_WILDCARD);
		
	}

	static public boolean isFloatOrDouble(byte dt) {
		return dt == DT_DOUBLE;
	}

	static public byte getDataType(String datatype) {
		Byte dt = dtMap.get(datatype);
		if (dt != null)
			return dt;
		return -1;
	}

	static public String getDataType(byte datatype) {
		String dt = revertDTMap.get(datatype);
		return dt;
	}

	@SuppressWarnings("unchecked")
	public static <T> T getMaxValue(T instance) {
		if (instance instanceof Double) {
			return (T) Double.valueOf(Double.POSITIVE_INFINITY);
		} else if (instance instanceof Long) {
			return (T) Long.valueOf(Long.MAX_VALUE);
		} else if (instance instanceof String) {
			return (T) MAX_STRING;
		} else if (instance instanceof Boolean) {
			return (T) Boolean.TRUE;
		}

		throw new RuntimeException(
				"do not support to fetch the max value of an instance of "
						+ instance.getClass().toString());
	}

	@SuppressWarnings("unchecked")
	public static <T> T getMinValue(T instance) {
		if (instance instanceof Double) {
			return (T) Double.valueOf(Double.NEGATIVE_INFINITY);
		} else if (instance instanceof Long) {
			return (T) Long.valueOf(Long.MIN_VALUE);
		} else if (instance instanceof String) {
			return (T) MIN_STRING;
		} else if (instance instanceof Boolean) {
			return (T) Boolean.FALSE;
		} 

		throw new RuntimeException(
				"do not support to fetch the max value of an instance of "
						+ instance.getClass().toString());
	}
	
	public static boolean isArray(byte b){
		if (b == DT_DOUBLE_ARRAY || b == DT_INT_ARRAY || b == DT_STRING_ARRAY) {
			return true;
		}else {
			return false;
		}
	}

	public static boolean isIntOrLong(byte b) {
		return DT_LONG == b;
	}

	public static boolean isString(byte b) {
		return DT_STRING == b;
	}

	public static boolean isDoubleArray(byte b) {
		return b == DT_DOUBLE_ARRAY;
	}

	public static boolean isLongArray(byte b) {
		return  b == DT_INT_ARRAY;
	}

	public static boolean isStringArray(byte b) {
		return b == DT_STRING_ARRAY;
	}
	
	public static boolean isWildCard(byte b){
		return b == DT_WILDCARD;
	}
}
